package handlers

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

// WechatConfig 微信配置结构体
type WechatConfig struct {
	WechatAppID     string
	WechatAppSecret string
	BackendURL      string
	FrontendURL     string
}

// 微信AccessToken响应
type WechatTokenResponse struct {
	AccessToken  string `json:"access_token"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	OpenID       string `json:"openid"`
	Scope        string `json:"scope"`
	ErrCode      int    `json:"errcode"`
	ErrMsg       string `json:"errmsg"`
}

// 微信用户信息响应
type WechatUserInfo struct {
	OpenID     string `json:"openid"`
	Nickname   string `json:"nickname"`
	Sex        int    `json:"sex"`
	Province   string `json:"province"`
	City       string `json:"city"`
	Country    string `json:"country"`
	HeadImgURL string `json:"headimgurl"`
	UnionID    string `json:"unionid"`
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
}

// 通用API响应
type APIResponse struct {
	Success bool        `json:"success"`
	Message string      `json:"message,omitempty"`
	Data    interface{} `json:"data,omitempty"`
}

// 全局微信配置
var wechatConfig *WechatConfig

// State管理（用于防止CSRF攻击）
var (
	stateStore = make(map[string]time.Time)
	stateMutex sync.RWMutex
	stateTTL   = 10 * time.Minute // State有效期10分钟
)

// 清理过期的State（定期清理）
func init() {
	go func() {
		ticker := time.NewTicker(5 * time.Minute)
		defer ticker.Stop()
		for range ticker.C {
			cleanExpiredStates()
		}
	}()
}

// cleanExpiredStates 清理过期的State
func cleanExpiredStates() {
	stateMutex.Lock()
	defer stateMutex.Unlock()

	now := time.Now()
	for state, expireTime := range stateStore {
		if now.After(expireTime) {
			delete(stateStore, state)
		}
	}
}

// saveState 保存State（带过期时间）
func saveState(state string) {
	stateMutex.Lock()
	defer stateMutex.Unlock()
	stateStore[state] = time.Now().Add(stateTTL)
}

// validateState 验证State是否有效
func validateState(state string) bool {
	stateMutex.RLock()
	defer stateMutex.RUnlock()

	expireTime, exists := stateStore[state]
	if !exists {
		return false
	}

	if time.Now().After(expireTime) {
		// 已过期，删除
		stateMutex.RUnlock()
		stateMutex.Lock()
		delete(stateStore, state)
		stateMutex.Unlock()
		stateMutex.RLock()
		return false
	}

	// 验证成功后删除（一次性使用）
	stateMutex.RUnlock()
	stateMutex.Lock()
	delete(stateStore, state)
	stateMutex.Unlock()
	return true
}

// InitWechatConfig 初始化微信配置（从配置文件加载）
func InitWechatConfig(appID, appSecret, backendURL, frontendURL string) {
	// 如果 frontendURL 为空，使用默认值
	if frontendURL == "" {
		frontendURL = "http://localhost:5500"
	}

	wechatConfig = &WechatConfig{
		WechatAppID:     appID,
		WechatAppSecret: appSecret,
		BackendURL:      backendURL,
		FrontendURL:     frontendURL,
	}

	log.Printf("[微信配置] 初始化完成 - AppID: %s, BackendURL: %s, FrontendURL: %s",
		maskString(appID), backendURL, frontendURL)
}

// maskString 掩码显示敏感信息（只显示前4位和后4位）
func maskString(s string) string {
	if len(s) <= 8 {
		return "****"
	}
	return s[:4] + "****" + s[len(s)-4:]
}

// loadWechatConfig 获取微信配置
func loadWechatConfig() *WechatConfig {
	if wechatConfig == nil {
		log.Println("[警告] 微信配置未初始化，使用默认配置")
		// 返回默认配置以避免 panic
		return &WechatConfig{
			WechatAppID:     "",
			WechatAppSecret: "",
			BackendURL:      "http://38131sx507pn.vicp.fun",
			FrontendURL:     "http://localhost:5500",
		}
	}
	return wechatConfig
}

// getFrontendURL 获取前端URL（用于回调重定向）
func getFrontendURL(c *gin.Context) string {
	config := loadWechatConfig()
	if config.FrontendURL != "" {
		return config.FrontendURL
	}

	// 如果没有配置，尝试从请求头获取
	referer := c.GetHeader("Referer")
	if referer != "" {
		// 从 Referer 中提取前端地址
		parsedURL, err := url.Parse(referer)
		if err == nil {
			// 移除路径部分，只保留协议和主机
			return fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
		}
	}

	// 尝试从 Origin 请求头获取
	origin := c.GetHeader("Origin")
	if origin != "" {
		return origin
	}

	// 默认返回（开发环境）
	return "http://localhost:5500"
}

// 生成随机状态字符串
func generateState() string {
	rand.Seed(time.Now().UnixNano())
	const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	result := make([]byte, 16)
	for i := range result {
		result[i] = chars[rand.Intn(len(chars))]
	}
	return string(result)
}

// HTTP GET 请求工具函数
func httpGet(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return io.ReadAll(resp.Body)
}

// GetWechatAuthURL 生成微信登录链接
func GetWechatAuthURL(c *gin.Context) {
	config := loadWechatConfig()

	// 检查必要配置
	if config.WechatAppID == "" || config.WechatAppSecret == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "微信登录未配置，请在 config.yaml 中配置 wechat.app_id 和 wechat.app_secret",
		})
		return
	}

	// 使用配置文件中的后端URL（微信回调必须使用固定域名）
	backendURL := config.BackendURL
	redirectURI := fmt.Sprintf("%s/wechat/callback", backendURL)
	state := generateState()

	// 保存State用于后续验证（防止CSRF攻击）
	saveState(state)

	authURL := fmt.Sprintf(
		"https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redirect",
		config.WechatAppID,
		url.QueryEscape(redirectURI),
		state,
	)

	log.Printf("[微信登录] 生成授权链接: %s", authURL)

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": map[string]string{
			"url":   authURL,
			"state": state,
		},
	})
}

// WechatCallback 微信回调接口 - OAuth核心流程
func WechatCallback(c *gin.Context) {
	config := loadWechatConfig()

	// 检查必要配置
	if config.WechatAppID == "" || config.WechatAppSecret == "" {
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "微信登录未配置，请在 config.yaml 中配置 wechat.app_id 和 wechat.app_secret")
		return
	}

	code := c.Query("code")
	state := c.Query("state")

	log.Printf("[微信回调] Code: %s, State: %s", code, state)

	if code == "" {
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "授权失败：未获取到code")
		return
	}

	// 验证State参数（防止CSRF攻击）
	if !validateState(state) {
		log.Printf("[微信回调] State验证失败: %s", state)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "授权失败：State验证失败，请重新登录")
		return
	}
	log.Printf("[微信回调] State验证成功")

	// 第一步：用code换取access_token
	tokenURL := fmt.Sprintf(
		"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
		config.WechatAppID,
		config.WechatAppSecret,
		code,
	)

	tokenData, err := httpGet(tokenURL)
	if err != nil {
		log.Printf("[微信回调] 获取access_token失败: %v", err)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "获取access_token失败")
		return
	}

	var tokenResp WechatTokenResponse
	if err := json.Unmarshal(tokenData, &tokenResp); err != nil {
		log.Printf("[微信回调] 解析token响应失败: %v", err)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "解析微信响应失败")
		return
	}

	// 检查微信返回的错误
	if tokenResp.ErrCode != 0 {
		log.Printf("[微信回调] 微信token接口返回错误: %d - %s", tokenResp.ErrCode, tokenResp.ErrMsg)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, fmt.Sprintf("微信错误: %s", tokenResp.ErrMsg))
		return
	}

	log.Printf("[微信回调] 成功获取access_token, OpenID: %s", tokenResp.OpenID)

	// 第二步：获取用户信息
	userInfoURL := fmt.Sprintf(
		"https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN",
		tokenResp.AccessToken,
		tokenResp.OpenID,
	)

	userData, err := httpGet(userInfoURL)
	if err != nil {
		log.Printf("[微信回调] 获取用户信息失败: %v", err)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "获取用户信息失败")
		return
	}

	var userInfo WechatUserInfo
	if err := json.Unmarshal(userData, &userInfo); err != nil {
		log.Printf("[微信回调] 解析用户信息失败: %v", err)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "解析用户信息失败")
		return
	}

	// 检查用户信息接口错误
	if userInfo.ErrCode != 0 {
		log.Printf("[微信回调] 微信用户信息接口返回错误: %d - %s", userInfo.ErrCode, userInfo.ErrMsg)
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, fmt.Sprintf("获取用户信息失败: %s", userInfo.ErrMsg))
		return
	}

	log.Printf("[微信回调] 获取用户信息成功: %s (%s)", userInfo.Nickname, userInfo.OpenID)

	// 构建用户信息JSON
	userInfoJSON, err := json.Marshal(map[string]string{
		"nickname":   userInfo.Nickname,
		"headimgurl": userInfo.HeadImgURL,
		"openid":     userInfo.OpenID,
		"province":   userInfo.Province,
		"city":       userInfo.City,
	})
	if err != nil {
		frontendURL := getFrontendURL(c)
		redirectWithError(c, frontendURL, "构建用户信息失败")
		return
	}

	// 获取前端URL（用于回调重定向）
	frontendURL := getFrontendURL(c)

	// 构建登录页面URL
	// 对于H5平台，使用hash路由格式：/#/pages/auth/login/login
	// 对于APP平台，可能需要使用自定义协议
	loginPath := "/#/pages/auth/login/login"
	loginURL := fmt.Sprintf("%s%s?success=true&user=%s",
		frontendURL,
		loginPath,
		url.QueryEscape(string(userInfoJSON)),
	)

	log.Printf("[微信回调] 重定向到前端: %s", loginURL)
	c.Redirect(http.StatusFound, loginURL)
}

// redirectWithError 重定向到前端并显示错误
func redirectWithError(c *gin.Context, frontendURL, message string) {
	// 构建登录页面URL（使用hash路由格式）
	loginPath := "/#/pages/auth/login/login"
	loginURL := fmt.Sprintf("%s%s?success=false&message=%s",
		frontendURL,
		loginPath,
		url.QueryEscape(message),
	)
	log.Printf("[微信回调] 重定向到前端（错误）: %s", loginURL)
	c.Redirect(http.StatusFound, loginURL)
}
